% TEST_ID: LANG-EXPAND-0053
% CATEGORY: language/reflection
% 测试 eval 函数

function test_eval
    test_entry();

    y = 7;

    m = eval('1');
    assert(m == 1);

    n = eval('multi_return()');
    assert(n == 1);

    % test中的赋值不应该修改repl作用域，应该在局部作用域中创建变量
    assert(y == 7)

    a = 13;
    test1();
    assert(a == 13)

    test_func()

    test_nested_eval()

    test_nested_eval_read_and_write()
    test_func_call_inside_eval()
    test_eval_return()
    test_eval_no_ans()
    test_lambda()
    test_eval_dynamic_scope()
end

function test_entry()
    x = 1;
    eval('x')
    eval('y = x + 1;');
    assert(y == 2);
    eval('assert(x+1 == y);');

    k = 1;
    eval('k = 2;');
    assert(k == 2);
end

function test1()
    a = 17;
    eval('a = 18;');
end

function test_func()
    function output = inner_func()
        output = 23;
    end
    eval('assert(inner_func() == 23)');
end


function test_nested_eval()
    function output = inner_func3()
        output = 2
    end
end


function test_nested_eval_read_and_write()
    x_at_entry = 7;
    function inner_func4()
        x_at_inner_func4 = 1;
        eval('assert(x_at_entry == 7);');               % 读1层自由变量
        function inner_func5()
            eval('assert(x_at_inner_func4 == 1);');     % 读1层自由变量
            eval('x_at_inner_func4 = 3;');              % 写1层自由变量
            eval('assert(x_at_inner_func4 == 3);');
            eval('assert(x_at_entry == 7);');           % 读2层自由变量
            eval('x_at_entry = 8;');                    % 写2层自由变量
        end
        eval('inner_func5();');
        assert(x_at_inner_func4 == 3);                  % x_at_inner_func4成功被inner_func5写入
        assert(x_at_entry == 8);                        % x_at_entry成功被inner_func5写入
        eval('x_at_inner_func4 = 5;');                  % 写1层自由变量
        assert(x_at_inner_func4 == 5);                  % x_at_inner_func4成功被自己写入
    end
    eval('inner_func4()');
end

function test_func_call_inside_eval()
    function inner_func2()
        % 需要确保以下x的访问会报错
        assert(~exist('x', 'var'))
    end
    function inner_func1()
        x = 1;
        inner_func2();
        eval('inner_func2()')
    end
    inner_func1()
end

function test_eval_return()
    function [a,b,c] = inner_func()
        a = 1;
        b = 2;
        c = 3;
    end
    ans = 999;
    y = eval('1');
    assert(y == 1);
    y = eval('inner_func()');
    assert(y == 1);
    y = eval('1 + 1');
    assert(y == 2);
    assert(isequal(ans, 999));
    eval('')
    assert(isequal(ans, 999));
end

function test_eval_no_ans()
    y = eval('1');
    assert(y == 1);
end

function [a,b,c] = multi_return()
    a = 1;
    b = 2;
    c = 3;
end

function test_eval_dynamic_scope()
    eval('x_dyn=1;');
    assert(x_dyn == 1)
    kk = eval('multi_return()');
    assert(kk == 1);
    [kk_a, kk_b] = eval('multi_return()');
    assert(kk_a == 1);
    assert(kk_b == 2);

    % eval支持传递nargout
    [a, b, c] = eval('multi_return2()');
    assert(a == 3);
    assert(b == 3);
    assert(c == 3);
end

function varargout = multi_return2()
    for i = 1:nargout
      varargout{i} = nargout;
    end
end

function test_lambda()
    eval('f1 = @() 24;');
    assert(f1() == 24);
end